﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.IO;
using System.Reflection;
using WeifenLuo.WinFormsUI.Docking;
using T3K.SketchEditor;
using T3K.SketchEditor.Configuration;
using T3K.SketchEditor.Core;
using T3K.SketchEditor.Forms;

namespace T3K.SketchEditor.Plugins {

    public class SketchPlugin : PluginBase {

        private Project _project;
        private const string ProjectVar = "Project";
//        private ProjectExplorer _projectExplorer;
        private System.Windows.Forms.SaveFileDialog _saveFileDialog;
        private System.Windows.Forms.OpenFileDialog _openFileDialog;

        public SketchPlugin() : base("SketchPlugin") {
            _saveFileDialog = new SaveFileDialog();
            _openFileDialog = new OpenFileDialog();

            _openFileDialog.Filter = "Sketch Project (*.skt)| *.skt";
            _saveFileDialog.Filter = "Sketch Project (*.skt)| *.skt";
        }

        public override bool Init() {

            ToolStripMenuItem   sketchMenu      = new ToolStripMenuItem("Sketch");
            ToolStripMenuItem   sketchNew       = new ToolStripMenuItem("New");
            ToolStripMenuItem   sketchOpen      = new ToolStripMenuItem("Open");
            ToolStripMenuItem   sketchSave      = new ToolStripMenuItem("Save");
            //ToolStripMenuItem   sketchSaveAs    = new ToolStripMenuItem("SaveAs");
            ToolStripSeparator  sep1            = new ToolStripSeparator();
            ToolStripMenuItem   sketchCompile   = new ToolStripMenuItem("Compile / Verify");
            ToolStripMenuItem   sketchUpload    = new ToolStripMenuItem("Upload");
            ToolStripMenuItem   sketchDumpConf  = new ToolStripMenuItem("Dump Build Configuration");
            ToolStripSeparator  sep2            = new ToolStripSeparator();
            ToolStripMenuItem   showExplorer    = new ToolStripMenuItem("Project Explorer");

            sketchNew.Click += new EventHandler(sketchNew_Click);
            sketchOpen.Click += new EventHandler(sketchOpen_Click);
            sketchSave.Click += new EventHandler(sketchSave_Click);
            //sketchSaveAs.Click += new EventHandler(sketchSaveAs_Click);
            sketchCompile.Click += new EventHandler(sketchCompile_Click);
            sketchUpload.Click += new EventHandler(sketchUpload_Click);
            sketchDumpConf.Click += new EventHandler(sketchDumpConf_Click);
            showExplorer.Click += new EventHandler(showExplorer_Click);

            sketchMenu.DropDownItems.AddRange (
                new ToolStripItem[] { 
                    sketchNew, sketchOpen, sketchSave, //sketchSaveAs,
                    sep1, sketchCompile, sketchUpload, sketchDumpConf, sep2, showExplorer
                }
            );

            MainMenu_InsertItemAfter(sketchMenu, "Edit");

            MainForm_RegisterForm("ProjectExplorer", typeof(ProjectExplorer), DockState.DockLeft, true);
            Editor.RegisterVariable(ProjectVar, new EditorVariable(_project));

            #region getMenus

            #endregion

            Editor.Register_EventHandler(this, "Output.DoubleClick");
            Editor.EditorEvent += new EditorEventHandler(Editor_EditorEvent);

            return true;
        }

        void Editor_EditorEvent(object sender, EditorEventArgs args) {
            if (args.EventType == "Output.DoubleClick") {
                string line = args["Line"] as string;
                Match match = Regex.Match(line, "\\s*([a-zA-Z]:[a-zA-Z0-9/ ._-]+):([0-9]+)", RegexOptions.Singleline);
                if (match.Success) {
                    if (match.Groups[1].Success && match.Groups[2].Success) {
                        string strLineNum = match.Groups[2].Value;
                        string strFileName = match.Groups[1].Value;
                        int lineNumber;
                        if (!int.TryParse(strLineNum, out lineNumber)) lineNumber = 1;
                        if (File.Exists(strFileName)) {

                            CommandArgs foArgs = new CommandArgs();
                            foArgs["FileName"] = strFileName;
                            foArgs["LineNum"] = lineNumber;

                            Editor.InvokeCommand(this, "Main.OpenFile", foArgs);
                        }
                    }
                }
            }
        }

        #region Methods
        public void Upload() {
            if (_project != null) {

                Editor.InvokeCommand(this, "Main.Output.WriteLine", new CommandArgs("Out", "-- Starting sketch upload ---------------"));

                _project["AppPath"] = System.IO.Directory.GetCurrentDirectory().Replace('\\', '/');

                string command = Path.Combine(Application.StartupPath, "AvrBuilder.exe");
                string arguments = " -c UPLOAD";
                string workingDir = _project.ProjectDir;
                Dictionary<string, string> envVars = new Dictionary<string, string>();

                StreamWriter sw = new StreamWriter(File.Open(
                    Path.Combine(_project.ProjectDir, "avrbuilder.vars"), FileMode.Create));

                foreach (Project.ProjectProperty prop in _project.Properties) {
                    sw.WriteLine("{0} = {1}", prop.Name, prop.Value);
                }

                sw.Flush();
                sw.Close();

                CommandArgs execArgs = new CommandArgs();
                execArgs["Command"] = command;
                execArgs["Arguments"] = arguments;
                execArgs["WorkingDir"] = workingDir;
                execArgs["EnviromentVars"] = envVars;

                Editor.InvokeCommand(this, "ExecPlugin.Execute", execArgs);
            } else
                Editor.InvokeCommand(this, "Main.Output.WriteLine",
                    new CommandArgs("Out", "Nothing to upload"));
        }

        public void DumpBuildConfiguration() {
            if (_project != null) {

                _project["AppPath"] = System.IO.Directory.GetCurrentDirectory().Replace('\\', '/');

                Editor.InvokeCommand(this, "Main.Output.WriteLine", new CommandArgs("Out", "-- Starting configuration dump ---------------"));

                string command = Path.Combine(Application.StartupPath, "AvrBuilder.exe");
                string arguments = " -c DUMPVARS";
                string workingDir = _project.ProjectDir;
                Dictionary<string, string> envVars = new Dictionary<string, string>();

                CommandArgs execArgs = new CommandArgs();
                execArgs["Command"] = command;
                execArgs["Arguments"] = arguments;
                execArgs["WorkingDir"] = workingDir;
                execArgs["EnviromentVars"] = envVars;

                Editor.InvokeCommand(this, "ExecPlugin.Execute", execArgs);
            } else
                Editor.InvokeCommand(this, "Main.Output.WriteLine",
                    new CommandArgs("Out", "Nothing to dump"));
        }

        public void Compile() {

            if (_project != null) {

                Editor.InvokeCommand(this, "Main.SaveAll");

                _project["AppPath"] = System.IO.Directory.GetCurrentDirectory().Replace('\\', '/');

                List<string> sourceFiles = _project.GetSourceFiles();
                string filesSrcPath = Path.Combine(_project.ProjectDir, "files.src");

                StreamWriter sw = new StreamWriter(File.Open(filesSrcPath, FileMode.Create));
                sw.WriteLine("PSRC:");
                for (int i = 0; i < sourceFiles.Count; i++)
                    sw.WriteLine(sourceFiles[i]);

                sw.Flush();
                sw.Close();

                Editor.InvokeCommand(this, "Main.Output.WriteLine", new CommandArgs("Out", "-- Starting sketch compilation ---------------"));

                string command = Path.Combine(Application.StartupPath, "AvrBuilder.exe");
                string arguments = " -i files.src -c BUILD";
                string workingDir = _project.ProjectDir;
                Dictionary<string, string> envVars = new Dictionary<string, string>();

                sw = new StreamWriter(File.Open(
                    Path.Combine(_project.ProjectDir, "avrbuilder.vars"), FileMode.Create));

                foreach (Project.ProjectProperty prop in _project.Properties) {
                    sw.WriteLine("{0} = {1}", prop.Name, prop.Value);
                }

                sw.Flush();
                sw.Close();

                CommandArgs execArgs = new CommandArgs();
                execArgs["Command"] = command;
                execArgs["Arguments"] = arguments;
                execArgs["WorkingDir"] = workingDir;
                execArgs["EnviromentVars"] = envVars;

                Editor.InvokeCommand(this, "ExecPlugin.Execute", execArgs);
            } else
                Editor.InvokeCommand(this, "Main.Output.WriteLine",
                    new CommandArgs("Out", "Nothing to compile"));
        }

        public void SaveAs() {
            _saveFileDialog.FileName = _project.ProjectName;
            _saveFileDialog.DefaultExt = ".skt";
            if (_saveFileDialog.ShowDialog() == DialogResult.OK) {
                _project.ProjectFilePath = _saveFileDialog.FileName;
                _project.ProjectName = (new FileInfo(_saveFileDialog.FileName)).Name;
                _project.Save();
                Editor.SetVariable(ProjectVar, _project);
                Editor.InvokeCommand(this, "ProjectExplorer.RefreshProject", new CommandArgs());
            }
        }

        public void Save() {
            if (_project != null) {
                if (string.IsNullOrEmpty(_project.ProjectFilePath))
                    SaveAs();
                else {
                    _project.Save();
                }
            }
        }

        public void Open() {
            if (_openFileDialog.ShowDialog() == DialogResult.OK) {
                string fileName = _openFileDialog.FileName;
                _project = Project.Open(fileName);
                Editor.SetVariable(ProjectVar, _project);
                Editor.InvokeCommand(this, "ProjectExplorer.LoadProject", new CommandArgs("Project", _project));
            }
        }

        public void New() {

            NewSketchForm form = new NewSketchForm();

            if (form.ShowDialog() == DialogResult.OK) {
                _project = form.Project;
                Editor.SetVariable(ProjectVar, _project);
                Editor.InvokeCommand(this, "ProjectExplorer.LoadProject", new CommandArgs("Project", _project));
                this.Save();
            }
        }
        #endregion

        #region Menu EventHandlers
        void showExplorer_Click(object sender, EventArgs e) {
            MainForm_Show("ProjectExplorer");
        }

        void sketchUpload_Click(object sender, EventArgs e) {
            Upload();
        }

        void sketchCompile_Click(object sender, EventArgs e) {
            Compile();
        }

        void sketchDumpConf_Click(object sender, EventArgs e) {
            DumpBuildConfiguration();
        }

        void sketchSaveAs_Click(object sender, EventArgs e) {
            SaveAs();
        }

        void sketchSave_Click(object sender, EventArgs e) {
            Save();
        }

        void sketchOpen_Click(object sender, EventArgs e) {
            Open();
        }

        void sketchNew_Click(object sender, EventArgs e) {
            New();
        }
        #endregion

        #region Commands

        [Command("GetProject")]
        public void Command_GetProject(object sender, CommandArgs args) {
            args.Return.Data = _project;
        }

        [Command("AddFile")]
        public void Command_AddFile(object sender, CommandArgs args) {

        }

        [Command("RemoveFile")]
        public void Command_RemoveFile(object sender, CommandArgs args) {

        }

        [Command("CreateSketch")]
        public void Command_CreateSketch(object sender, CommandArgs args) {
            New();
        }

        [Command("OpenSketch")]
        public void Command_OpenSketch(object sender, CommandArgs args) {
            Open();
        }

        [Command("SaveSketch")]
        public void Command_SaveSketch(object sender, CommandArgs args) {
            Save();
        }

        [Command("SaveSketchAs")]
        public void Command_SaveSketchAs(object sender, CommandArgs args) {
            SaveAs();
        }
        #endregion

    }
}

